/*
 * Mat2.h
 *
 *  Created on: 20.09.2009
 *      Author: christoph
 */

#ifndef MAT2_H_
#define MAT2_H_

#include "System.h"
#include "math/Math.h"
#include "types/Vec2.h"

namespace mehari {
namespace common {

template <typename Real>
class Vec2;

template < typename Real >
class Mat2 {
public:
	Mat2();
	Mat2( const Real r0, const Real r1, const Real r2, const Real r3 );
	Mat2( const Real matrix[4] );
	Mat2( const Mat2& m2 );
	~Mat2();

	// access
	const Real* operator[] ( int iRow ) const;
	Real* operator [] ( int iRow );
	Real operator () ( int iRow, int iCol ) const;
	Real& operator () ( int iRow, int ICol );

	void setRow( int iRow, const Vec2<Real>& v2Val );
	void setCol( int iCol, const Vec2<Real>& v2Val );

	Vec2<Real> getRow( int iRow ) const;
	Vec2<Real> getCol( int iCol ) const;

	void setZero();
	void setIdentity();

	// assignment
	Mat2<Real>& operator = ( const Mat2<Real>& mRhs );

	// arithmetic operations
	Mat2<Real> operator + ( const Mat2<Real>& mRhs ) const;
	Mat2<Real> operator - ( const Mat2<Real>& mRhs ) const;
	Mat2<Real> operator * ( const Real rRhs ) const;
	Mat2<Real> operator / ( const Real rRhs ) const;

	Mat2<Real> operator += ( const Mat2<Real>& mRhs );
	Mat2<Real> operator -= ( const Mat2<Real>& mRhs );
	Mat2<Real> operator *= ( const Real rRhs );
	Mat2<Real> operator /= ( const Real rRhs );

	// comparison operations
	bool operator == ( const Mat2<Real>& mRhs ) const;
	bool operator != ( const Mat2<Real>& mRhs ) const;
	bool operator <  ( const Mat2<Real>& mRhs ) const;
	bool operator <= ( const Mat2<Real>& mRhs ) const;
	bool operator >  ( const Mat2<Real>& mRhs ) const;
	bool operator >= ( const Mat2<Real>& mRhs ) const;

	// geometric operations
	/**
	 * matrix must be a rotation matrix
	 */
	Real toAngle() const;
	/**
	 * matrix must be a rotation matrix.
	 * Applies Gram-Schmidt orthonormalization to its columns. The first column is nor-
	 * malized, and the second column is adjusted by subtracting out its projection onto
	 * the normalized first column. This operation is useful when the rotation is updated
	 * frequently through concatenation with other matrices. Over time, the numerical
	 * round-off errors can accumulate, and the matrix strays from having the properties
	 * of a rotation. An adjustment such as Gram-Schmidt orthonormalization restores the
	 * matrix to a rotation.
	 */
	void orthoNormalize();
	/**
	 * matrix must be symmetric.
	 */
	void eigenDecomposition( Mat2& m2Rot, Mat2& m2Diag ) const;

	// Mat2 * Vec2
	Vec2<Real> operator * ( const Vec2<Real>& v2Rhs ) const;

	// other
	Mat2<Real> transpose() const;
	Mat2<Real> inverse() const;
	Mat2<Real> adjoint() const;
	Real determinant() const;


private:
	/**
	 * holds the data
	 * 0 1
	 * 2 3
	 */
	Real data[4];
};

} // namespace common
} // namespace mehari

#include "../src/types/Mat2.cpp.inl"



#endif /* MAT2_H_ */
